/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tictactoe;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
/**
 *
 * @author Kevin O
 */
public class DrawPanel extends JPanel{
    
    
    int rotation = ROTATION_WX;
    
    int display_mode = BOARD_DISPLAY;
    
    MarkedSquare[] highlighted_squares;
    boolean diagonal_is_highlighted;
    
    //Constants for board rotation
    static final int ROTATION_WX = 0;
    static final int ROTATION_WY = 1;
    static final int ROTATION_WZ = 2;
    static final int ROTATION_XY = 3;
    static final int ROTATION_XZ = 4;
    static final int ROTATION_YZ = 5;
    
    static final int BOARD_DISPLAY = 0;
    static final int DIAGONAL_DISPLAY = 1;
    
    private Game game;
    
    public DrawPanel(Game g){
        setSize(500,500);
        this.setBackground(Color.WHITE);
        game = g;
        highlighted_squares = new MarkedSquare[4];
        diagonal_is_highlighted = false;
    }
    
    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g;
        
        //Draws the normal game board
        if (display_mode == BOARD_DISPLAY){
            //checkerboards the game board, to more easily distinguish the sub-boards
            g2d.setColor(new Color(0.9f, 0.9f, 0.9f));
            g2d.fillRect(getWidth() / 4, 0, getWidth() / 4, getHeight() / 4);
            g2d.fillRect(3 * getWidth() / 4, 0, getWidth() / 4, getHeight() / 4);
        
            g2d.fillRect(0, getHeight() / 4, getWidth() / 4, getHeight() / 4);
            g2d.fillRect(getWidth() / 2, getHeight() / 4, getWidth() / 4, getHeight() / 4);
        
            g2d.fillRect(getWidth() / 4, getHeight() / 2, getWidth() / 4, getHeight() / 4);
            g2d.fillRect(3 * getWidth() / 4, getHeight() / 2, getWidth() / 4, getHeight() / 4);
        
            g2d.fillRect(0, 3 * getHeight() / 4, getWidth() / 4, getHeight() / 4);
            g2d.fillRect(getWidth() / 2, 3 * getHeight() / 4, getWidth() / 4, getHeight() / 4);
            
            //highlights the selected square for diagonals
            if(diagonal_is_highlighted){
                switch(rotation){
                    case ROTATION_WX:
                        for (int i = 0; i < 4; i++){
                            highlightSquare(g2d, highlighted_squares[i].coord3, highlighted_squares[i].coord4,
                                    highlighted_squares[i].coord1, highlighted_squares[i].coord2, Color.YELLOW);
                        }
                        break;
                    case ROTATION_WY:
                        for (int i = 0; i < 4; i++){
                            highlightSquare(g2d, highlighted_squares[i].coord2, highlighted_squares[i].coord4,
                                    highlighted_squares[i].coord1, highlighted_squares[i].coord3, Color.YELLOW);
                        }
                        break;
                    case ROTATION_WZ:
                        for (int i = 0; i < 4; i++){
                            highlightSquare(g2d, highlighted_squares[i].coord2, highlighted_squares[i].coord3,
                                    highlighted_squares[i].coord1, highlighted_squares[i].coord4, Color.YELLOW);
                        }
                        break;
                    case ROTATION_XY:
                        for (int i = 0; i < 4; i++){
                            highlightSquare(g2d, highlighted_squares[i].coord1, highlighted_squares[i].coord4,
                                    highlighted_squares[i].coord2, highlighted_squares[i].coord3, Color.YELLOW);
                        }
                        break;
                    case ROTATION_XZ:
                        for (int i = 0; i < 4; i++){
                            highlightSquare(g2d, highlighted_squares[i].coord1, highlighted_squares[i].coord3,
                                    highlighted_squares[i].coord2, highlighted_squares[i].coord4, Color.YELLOW);
                        }
                        break;
                    case ROTATION_YZ:
                        for (int i = 0; i < 4; i++){
                            highlightSquare(g2d, highlighted_squares[i].coord1, highlighted_squares[i].coord2,
                                    highlighted_squares[i].coord3, highlighted_squares[i].coord4, Color.YELLOW);
                        }
                        break;
                }
            }
            
            //Retrieve data for drawing x's and o's
            SquareColor[][][][] gamestate = game.update();
            for(int i = 0; i < 4; i++){
                for(int j = 0; j < 4; j++){
                    for(int k = 0; k < 4; k++){
                        for(int l = 0; l < 4; l++){
                            //A disgusting switch to handle the board rotation
                            switch(rotation){
                                case ROTATION_WX:
                                    if(gamestate[i][j][k][l] == SquareColor.Xthreat)
                                        highlightSquare(g2d, k, l, i, j, new Color(0.5f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.Othreat)
                                        highlightSquare(g2d, k, l, i, j, new Color(1f, 0.5f, 0.5f));
                                    else if(gamestate[i][j][k][l] == SquareColor.Boththreat)
                                        highlightSquare(g2d, k, l, i, j, new Color(1f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.X)
                                        drawX(g2d, k, l, i, j);
                                    else if(gamestate[i][j][k][l] == SquareColor.O)
                                        drawO(g2d, k, l, i, j);
                                    break;
                               case ROTATION_WY:
                                    if(gamestate[i][j][k][l] == SquareColor.Xthreat)
                                        highlightSquare(g2d, j, l, i, k, new Color(0.5f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.Othreat)
                                        highlightSquare(g2d, j, l, i, k, new Color(1f, 0.5f, 0.5f));
                                    else if(gamestate[i][j][k][l] == SquareColor.Boththreat)
                                        highlightSquare(g2d, j, l, i, k, new Color(1f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.X)
                                        drawX(g2d, j, l, i, k);
                                    else if(gamestate[i][j][k][l] == SquareColor.O)
                                        drawO(g2d, j, l, i, k);
                                    break;
                               case ROTATION_WZ:
                                    if(gamestate[i][j][k][l] == SquareColor.Xthreat)
                                        highlightSquare(g2d, j, k, i, l, new Color(0.5f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.Othreat)
                                        highlightSquare(g2d, j, k, i, l, new Color(1f, 0.5f, 0.5f));
                                    else if(gamestate[i][j][k][l] == SquareColor.Boththreat)
                                        highlightSquare(g2d, j, k, i, l, new Color(1f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.X)
                                        drawX(g2d, j, k, i, l);
                                    else if(gamestate[i][j][k][l] == SquareColor.O)
                                        drawO(g2d, j, k, i, l);
                                    break;
                               case ROTATION_XY:
                                    if(gamestate[i][j][k][l] == SquareColor.Xthreat)
                                        highlightSquare(g2d, i, l, j, k, new Color(0.5f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.Othreat)
                                        highlightSquare(g2d, i, l, j, k, new Color(1f, 0.5f, 0.5f));
                                    else if(gamestate[i][j][k][l] == SquareColor.Boththreat)
                                        highlightSquare(g2d, i, l, j, k, new Color(1f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.X)
                                        drawX(g2d, i, l, j, k);
                                    else if(gamestate[i][j][k][l] == SquareColor.O)
                                        drawO(g2d, i, l, j, k);
                                    break;
                               case ROTATION_XZ:
                                    if(gamestate[i][j][k][l] == SquareColor.Xthreat)
                                        highlightSquare(g2d, i, k, j, l, new Color(0.5f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.Othreat)
                                        highlightSquare(g2d, i, k, j, l, new Color(1f, 0.5f, 0.5f));
                                    else if(gamestate[i][j][k][l] == SquareColor.Boththreat)
                                        highlightSquare(g2d, i, k, j, l, new Color(1f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.X)
                                        drawX(g2d, i, k, j, l);
                                    else if(gamestate[i][j][k][l] == SquareColor.O)
                                        drawO(g2d, i, k, j, l);
                                    break;
                               case ROTATION_YZ:
                                    if(gamestate[i][j][k][l] == SquareColor.Xthreat)
                                        highlightSquare(g2d, i, j, k, l, new Color(0.5f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.Othreat)
                                        highlightSquare(g2d, i, j, k, l, new Color(1f, 0.5f, 0.5f));
                                    else if(gamestate[i][j][k][l] == SquareColor.Boththreat)
                                        highlightSquare(g2d, i, j, k, l, new Color(1f, 0.5f, 1));
                                    else if(gamestate[i][j][k][l] == SquareColor.X)
                                        drawX(g2d, i, j, k, l);
                                    else if(gamestate[i][j][k][l] == SquareColor.O)
                                        drawO(g2d, i, j, k, l);
                                    break;
                            }
                        }
                    }
                }
            }
            
            //Draws the tic-tac-toe sub-boards
            g2d.setColor(Color.BLACK);
            g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER));
            for(int i = 0; i < 4; i++){
                for(int j = 0; j < 4; j++){
                    //Vertical Lines
                    g2d.drawLine(i * getWidth() / 4 + 5 * getWidth() / 64,
                            j * getHeight() / 4 + getHeight() / 32, 
                            i * getWidth() / 4 + 5 * getWidth() / 64,
                            j * getHeight() / 4 + 7 * getHeight() / 32);
                    g2d.drawLine(i * getWidth() / 4 + getWidth() / 8,
                            j * getHeight() / 4 + getHeight() / 32, 
                            i * getWidth() / 4 + getWidth() / 8,
                            j * getHeight() / 4 + 7 * getHeight() / 32);
                    g2d.drawLine(i * getWidth() / 4 + 11 * getWidth() / 64,
                            j * getHeight() / 4 + getHeight() / 32, 
                            i * getWidth() / 4 + 11 * getWidth() / 64,
                            j * getHeight() / 4 + 7 * getHeight() / 32);
                
                    //Horizontal Lines
                    g2d.drawLine(i * getWidth() / 4 + getWidth() / 32,
                            j * getHeight() / 4 + 5 * getHeight() / 64, 
                            i * getWidth() / 4 + 7 * getWidth() / 32,
                            j * getHeight() / 4 + 5 * getHeight() / 64);
                    g2d.drawLine(i * getWidth() / 4 + getWidth() / 32,
                            j * getHeight() / 4 + getHeight() / 8, 
                            i * getWidth() / 4 + 7 * getWidth() / 32,
                            j * getHeight() / 4 + getHeight() / 8);
                    g2d.drawLine(i * getWidth() / 4 + getWidth() / 32,
                            j * getHeight() / 4 + 11 * getHeight() / 64, 
                            i * getWidth() / 4 + 7 * getWidth() / 32,
                            j * getHeight() / 4 + 11 * getHeight() / 64);
                }
            }
        }
        
        //Draw display for Diagonal cheat sheet
        else {
            MarkedSquare[][] diagonals = game.getDiagonals();
            for(int i = 0; i < 8; i++){
                for(int j = 0; j < 9; j++){
                    
                    //fill in circles that X has marked
                    g2d.setColor(Color.BLUE);
                    if(diagonals[i + j*8][0].marker == Marker.X)
                        g2d.fillOval(i * getWidth() / 8 + getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    if(diagonals[i + j*8][1].marker == Marker.X)
                        g2d.fillOval(i * getWidth() / 8 + 3 * getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    if(diagonals[i + j*8][2].marker == Marker.X)
                        g2d.fillOval(i * getWidth() / 8 + 5 * getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    if(diagonals[i + j*8][3].marker == Marker.X)
                        g2d.fillOval(i * getWidth() / 8 + 7 * getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    
                    //fill in circles that O has marked
                    g2d.setColor(Color.RED);
                    if(diagonals[i + j*8][0].marker == Marker.O)
                        g2d.fillOval(i * getWidth() / 8 + getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    if(diagonals[i + j*8][1].marker == Marker.O)
                        g2d.fillOval(i * getWidth() / 8 + 3 * getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    if(diagonals[i + j*8][2].marker == Marker.O)
                        g2d.fillOval(i * getWidth() / 8 + 5 * getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    if(diagonals[i + j*8][3].marker == Marker.O)
                        g2d.fillOval(i * getWidth() / 8 + 7 * getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    
                    //draw empty circles for diagonals
                    g2d.setColor(Color.BLACK);
                    g2d.drawOval(i * getWidth() / 8 + getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    g2d.drawOval(i * getWidth() / 8 + 3 * getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    g2d.drawOval(i * getWidth() / 8 + 5 * getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    g2d.drawOval(i * getWidth() / 8 + 7 * getWidth() / 80, 
                            j * getHeight() / 9 + getHeight() / 18, 
                            getWidth() / 40, getHeight() / 40);
                    
                }
            }
        }
        
        //Extract Data from GameLogic and draw info based on that
    }
    
    public void drawX(Graphics2D g2d, int majx, int majy, int minx, int miny){
        double x = majx * getWidth() / 4;
        double y = majy * getHeight() / 4;
        switch (minx){
            case 0:
                x += getWidth() / 32;
                break;
            case 1:
                x += 5 * getWidth() / 64;
                break;
            case 2:
                x += getWidth() / 8;
                break;
            case 3:
                x += 11 * getWidth() / 64;
                break;
        }
        
        switch (miny){
            case 0:
                y += getHeight() / 32;
                break;
            case 1:
                y += 5 * getHeight() / 64;
                break;
            case 2:
                y += getHeight() / 8;
                break;
            case 3:
                y += 11 * getHeight() / 64;
                break;
        }
        
        g2d.setColor(Color.BLUE);
        g2d.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g2d.drawLine((int)(x + getWidth() / 128), (int)(y + getHeight() / 128), 
                (int)(x + 3 * getWidth() / 64 - getWidth() / 128), (int)(y + 3 * getHeight() / 64 - getHeight() / 128));
        g2d.drawLine((int)(x + getWidth() / 128), (int)(y + 3 * getHeight() / 64 - getHeight() / 128), 
                (int)(x + 3 * getWidth() / 64 - getWidth() / 128), (int)(y + getHeight() / 128));
    }
    
    public void drawO(Graphics2D g2d, int majx, int majy, int minx, int miny){
        double x = majx * getWidth() / 4;
        double y = majy * getHeight() / 4;
        switch (minx){
            case 0:
                x += getWidth() / 32;
                break;
            case 1:
                x += 5 * getWidth() / 64;
                break;
            case 2:
                x += getWidth() / 8;
                break;
            case 3:
                x += 11 * getWidth() / 64;
                break;
        }
        
        switch (miny){
            case 0:
                y += getHeight() / 32;
                break;
            case 1:
                y += 5 * getHeight() / 64;
                break;
            case 2:
                y += getHeight() / 8;
                break;
            case 3:
                y += 11 * getHeight() / 64;
                break;
        }
        
        g2d.setColor(Color.RED);
        g2d.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g2d.drawOval((int)(x + getWidth() / 128), (int)(y + getHeight() / 128), 
                (int)(3 * getWidth() / 64 - getWidth() / 64), (int)(3 * getHeight() / 64 - getHeight() / 64));
    }
    
    public void highlightSquare(Graphics2D g2d, int majx, int majy, int minx, int miny, Color c){
        double x = majx * getWidth() / 4;
        double y = majy * getHeight() / 4;
        switch (minx){
            case 0:
                x += getWidth() / 32;
                break;
            case 1:
                x += 5 * getWidth() / 64;
                break;
            case 2:
                x += getWidth() / 8;
                break;
            case 3:
                x += 11 * getWidth() / 64;
                break;
        }
        
        switch (miny){
            case 0:
                y += getHeight() / 32;
                break;
            case 1:
                y += 5 * getHeight() / 64;
                break;
            case 2:
                y += getHeight() / 8;
                break;
            case 3:
                y += 11 * getHeight() / 64;
                break;
        }
        
        g2d.setColor(c);
        g2d.fillRect((int)x, (int)y, (int)(3 * getWidth() / 64), (int)(3 * getHeight() / 64));
    }
    
}
